package com.qyer.commons.concurrent.assemblingline;

import com.qyer.commons.concurrent.GenericLinkedBlockingQueue;
import com.qyer.commons.concurrent.PoisonPill;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * User: Z J Wu Date: 2016/06/03 Time: 10:08 Package: com.qyer.commons.concurrent
 */
public final class Notifier<T extends PoisonPill<T>> {

  private static final Logger LOGGER = LoggerFactory.getLogger(Notifier.class);

  private final AtomicInteger counter = new AtomicInteger(0);

  private final int triggerValue;

  private final int nextConveyorPillCount;

  private final T poisonPillGenerator;

  private GenericLinkedBlockingQueue<T> nextConveyor;

  public Notifier(int triggerValue, GenericLinkedBlockingQueue<T> nextConveyor,
                  int nextConveyorPillCount, T poisonPillGenerator) {
    this.triggerValue = triggerValue;
    this.nextConveyor = nextConveyor;
    this.nextConveyorPillCount = nextConveyorPillCount;
    this.poisonPillGenerator = poisonPillGenerator;
  }

  public void finishAndNotify() {
    final int i = counter.incrementAndGet();
    if (i == triggerValue) {
      try {
        for (int j = 0; j < nextConveyorPillCount; j++) {
          this.nextConveyor.put(poisonPillGenerator.createPill());
        }
        LOGGER.info("Current phase is finished. Notified to next phase.");
      } catch (Exception e) {
        LOGGER.error("Notifier exit with exception.", e);
      }
    }
  }

  public int getNextConveyorPillCount() {
    return nextConveyorPillCount;
  }

  public static <T extends PoisonPill<T>> Notifier<T> newCommonNotifier(int triggerValue,
                                                                        GenericLinkedBlockingQueue<T> nextConveyor,
                                                                        int nextConveyorPillCount,
                                                                        T poisonPillGenerator) {
    Notifier<T> notifier = new Notifier<>(triggerValue, nextConveyor, nextConveyorPillCount,
                                          poisonPillGenerator);
    return notifier;
  }

  @Override
  public String toString() {
    StringBuilder sb = new StringBuilder();
    sb.append("Notifier(When reach ").append(triggerValue).append(" then put ")
      .append(nextConveyorPillCount).append(" to conveyor ").append(nextConveyor);
    return sb.toString();
  }
}
